/** 上传文件模块 */
const fs = require("fs"), path = require("path"), https = require("https"), readline = require("readline"), crypto = require('crypto');
const pinfo = require("./pinfo"), pan = require("../pan");

let basepath = "/apps/" + pan.name + "/", options = {
	hostname: 'pan.baidu.com',
	port: 443,
	path: '/',
	method: 'GET',
	headers: {
		'User-Agent': 'pan.baidu.com'
	}
};

/** 比较文件 */
function cmp(sp, lp, cb){
	if(sp[0] == '/' || sp[0] == '\\') sp = sp.substr(1);
	pinfo.listall(basepath + sp, (eno, fl)=>{
		if(eno){
			return cb();
		}
		let fids = [];
		//console.log(lp);
		check(lp, "/", sp, fl, fids);
		//console.log(fl);
		//console.log(fids);
		if(fids.length){
			upload(fids, lp, sp, 0, cb);
		}else{
			cb();
		}
	});
}

/* 检测文件 */
function check(lp, sub, sp, fl, fids){
	let fls = fs.readdirSync(lp + sub);
	//console.log("fls", sub, fls);
	for(let ff of fls){
		let fd = false;
		for(let f of fl){
			let cf = f.path.replace(basepath + sp + sub, '');
			if(cf == ff){
				fd = true;
				break;
			}
		}
		//console.log(lp + sub + ff);
		let stat = fs.statSync(lp + '/' + sub + '/' + ff, {throwIfNoEntry:false});
		if(!fd){
			//console.log(lp + '/' + sub + '/' + ff, stat);
			if(stat.isFile()){
				console.log(lp + sub + ff, stat.size, ">>> null");
				if(stat.size > 0){
					fids.push(lp + sub + ff);
				}else{
					console.log("空文件不传");
				}
			}else if(stat.isDirectory()){ //要传的新目录
				check(lp, sub + ff + "/", sp, fl, fids);
			}
		}else if(stat.isDirectory()){ //已存在的目录下比较
			check(lp, sub + ff + "/", sp, fl, fids)
		}					
	}
}
/* 上传文件 */
function upload(fls, lp, sp, index, cb){
	if(index >= fls.length){
		return cb();
	}
	//读取文件
	let fld = null, flname = path.basename(fls[index]), bt = Date.now(), block_list = [], reup = 0;
	fs.readFile(fls[index], (err, data)=>{
		if(err){
			console.log(fls[index], err)
			return;
		}else{
			fld = data;
			//计算md5
			let num = Math.ceil(fld.length / (4*1024*1024));
			//console.log("num", num);
			for(let i=0;i<num;i++){
				let md5 = crypto.createHash('md5');
				md5.update(fld.slice(i*4*1024*1024, i*4*1024*1024 + 4*1024*1024));
				let v = md5.digest('hex');
				block_list.push(v);
			}
			//上传
			let fl = fls[index].replace(lp, '');
			//console.log(block_list);
			if(fl[0] == '/') fl = fl.substr(1);
			precreate(fl, fld.length);
		}
	});
	//预上传
	function precreate(fl, size){
		console.log("[" + (index+1) + "/" + fls.length + "] 上传", fls[index]);
		let opt = JSON.parse(JSON.stringify(options));
		opt.path = "/rest/2.0/xpan/file?method=precreate&access_token=" + user.access_token;
		opt.method = "POST";
		let spath = basepath + (sp?sp + "/":"") + fl;
		let reqdata = "path=" + encodeURIComponent(spath) + "&size=" + size + "&isdir=0&autoinit=1&rtype=0&block_list=" + JSON.stringify(block_list);
		opt.headers['Content-Length'] = Buffer.byteLength(reqdata);
		//console.log(reqdata, sp, fl);
		let req = https.request(opt, (res)=>{
			let ret = Buffer.allocUnsafe(0);
			res.on('data', (chunk) => {
				ret = Buffer.concat([ret, chunk], ret.length + chunk.length);
			});
			res.on('end', () => {
				//console.log(ret.toString());
				let pre = JSON.parse(ret.toString());
				if(pre.errno){
					console.log("precreate", pre, reqdata);
					index++;
					upload(fls, lp, sp, index, cb);
				}else{
					if(pre.return_type == 2 || pre.block_list.length == 0){ //pre.block_list.length 文件已经上传了
						create(spath, size, pre.uploadid);
					}else{
						process.stdout.write("[0/" + fld.length + "]0.00% 0KB/s");
						superfile(spath, pre.uploadid, 0);
					}
				}
			});
		});
		req.on("error",(e)=>{
			console.log("precreate error", e);
			//继续上传下一个文件
			reup = 1;
			upload(fls, lp, sp, index, cb);
		})
		req.end(reqdata);
	}
	//分片上传
	function superfile(spath, uploadid, partseq){
		let opt = JSON.parse(JSON.stringify(options));
		opt.path = "/rest/2.0/pcs/superfile2?method=upload&access_token=" + user.access_token + "&type=tmpfile&path=" + encodeURIComponent(spath) + "&uploadid=" + uploadid + "&partseq=" + partseq;
		opt.method = "POST";
		opt.hostname = "d.pcs.baidu.com"
		//console.log(opt.path);
		//取4MB数据
		let sd = fld.slice(partseq*1024*1024*4, partseq*1024*1024*4 + 1024*1024*4);
		//opt.headers['content-type'] = 'multipart/form-data';
		//opt.headers['Content-Length'] = sd.length;
		//const FormData = require('form-data');
		//let form = new FormData();
		//form.append("file", sd);
		//console.log(form.getHeaders());
		//console.log("form", Buffer.isBuffer(sd), form.getBuffer());
		let boundary = "----Hong" + (Math.random()).toString().substr(-16) + Date.now();
		let sdstr = "--" + boundary + "\r\n"
		+ "Content-Disposition: form-data; name=\"file\"; filename=\"" + flname + "\"\r\n" //+ "\r\n";
		+ "Content-Type: application/octet-stream\r\n\r\n";
		
		delete opt.headers['User-Agent'];
		opt.headers['content-type'] = "multipart/form-data; boundary=" + boundary;
		opt.headers['Content-Length'] = Buffer.byteLength(sdstr) + sd.length + Buffer.byteLength(boundary) + 8;
		//opt.headers = form.getHeaders();
		//opt.headers['Content-Length'] = form.getLengthSync();
		//console.log(sd.length, form.getLengthSync(), form.getBuffer().length);
		//console.log(form.getBuffer().toString());
		//console.log(opt);
		//console.log(sdstr + sd.toString() + "\r\n--" + boundary + "--\r\n");
		//fs.writeFile("tt", form.getBuffer(), ()=>{});
		//let fdd = fs.openSync("./tt2", "w+");
		//fs.writeSync(fdd,sdstr);
		//fs.writeSync(fdd,sd);
		//fs.writeSync(fdd,"\r\n--" + boundary + "--\r\n");
		//fs.closeSync(fdd);
		let req = https.request(opt, (res)=>{
			let ret = Buffer.allocUnsafe(0)
			res.on('data', (chunk) => {
				ret = Buffer.concat([ret, chunk], ret.length + chunk.length);
			});
			res.on('end', () => {
				//console.log(ret.toString());
				let retstr = ret.toString();
				if(!retstr){
					console.log("superfile error ret null", res.statusCode);
					//重新上传 超过三暂时放弃
					reup++;
					if(reup > 3){
						index++;
						upload(fls, lp, sp, index, cb);						
					}else{
						superfile(spath, uploadid, partseq);
					}
					return;
				}
				let pre = JSON.parse(ret.toString());
				if(pre.error_code){
					console.log("superfile", pre);
					index++;
					upload(fls, lp, sp, index, cb);
				}else{
					readline.clearLine(process.stdout, 0);
					readline.cursorTo(process.stdout, 0);
					let csize = partseq*1024*1024*4 + 1024*1024*4;
					if(csize > fld.length) csize = fld.length;
					process.stdout.write("[" + csize + "/" + fld.length + "]" + (100*csize/fld.length).toFixed(2) + "% " + (csize / 1024 / ((Date.now() - bt) / 1000)).toFixed(2) + "KB/s");
					//block_list[partseq] = pre.md5; //md5值不一样应该错了
					if(csize < fld.length){
						partseq++;
						superfile(spath, uploadid, partseq);
					}else{
						create(spath, fld.length, uploadid);
					}
				}
			});
		});
		req.on("error",(e)=>{
			console.log("superfile error", e);
			//继续上传下一个文件
			reup = 0;
			index++;
			upload(fls, lp, sp, index, cb);
		})
		req.write(sdstr);
		req.write(sd);
		req.write("\r\n--" + boundary + "--\r\n");
		req.end();
		//req.end(form.getBuffer());
		//form.pipe(req);
	}
	//创建文件
	function create(spath, size, uploadid){
		let opt = JSON.parse(JSON.stringify(options));
		opt.path = "/rest/2.0/xpan/file?method=create&access_token=" + user.access_token;
		opt.method = "POST";
		let reqdata = "path=" + encodeURIComponent(spath) + "&size=" + size + "&isdir=0&rtype=0";
		if(uploadid){
			reqdata += "&uploadid=" + uploadid + "&block_list=" + JSON.stringify(block_list);
		}
		opt.headers['Content-Length'] = Buffer.byteLength(reqdata);
		let req = https.request(opt, (res)=>{
			let ret = Buffer.allocUnsafe(0);
			res.on('data', (chunk) => {
				ret = Buffer.concat([ret, chunk], ret.length + chunk.length);
			});
			res.on('end', () => {
				//console.log(ret.toString());
				let crt = JSON.parse(ret.toString());
				if(crt.errno){
					console.log("create", reqdata, crt);
				}else{
					console.log(" 完成");
				}
				reup = 0;
				index++;
				upload(fls, lp, sp, index, cb);
			});
		});
		req.on("error",(e)=>{
			console.log("create error", e);
			reup++;
			if(reup > 5){
				//继续上传下一个文件
				index++;
				upload(fls, lp, sp, index, cb);
			}else{
				create(spath, size, uploadid);
			}
		})
		req.end(reqdata);
	}
}

exports.cmp = cmp;
